fix: standalone dependency resolution#765
Conversation
commit: |
|
/bigbonk review |
There was a problem hiding this comment.
Good fix for two real issues in standalone dependency resolution. The changes are well-scoped and the tests cover the right scenarios.
Summary of what this does:
-
server-externals-manifest.ts—packageNameFromSpecifiernow correctly filters out Node builtins (crypto,fs/promises), virtual modules (virtual:vite-rsc), and intra-bundle file references (index.js,assets/chunk-abc.js). Previously these could leak into the externals manifest, causing the standalone BFS to try (and fail) to resolve them as npm packages. -
standalone.ts— Adds aresolve.paths()fallback for packages likersc-html-streamthat only expose subpath exports (e.g../serverbut not.or./package.json).resolver.resolve()can't access the package.json through the exports map, butresolve.paths()gives us thenode_moduleslookup directories to check directly.
Both fixes are correct and the tests are thorough. A couple of minor observations below, nothing blocking.
|
|
||
| // External specifiers can include non-package schemes such as | ||
| // "virtual:vite-rsc" or "file:...". Those are never npm packages. | ||
| if (/^[a-zA-Z][a-zA-Z\d+.-]*:/.test(specifier)) { |
There was a problem hiding this comment.
Minor: this regex matches RFC 3986 scheme syntax, which is the right call. Worth noting it also matches Windows drive letters like C:/path, but that's harmless since (a) those would never appear as Rollup external specifiers, and (b) the \\ startsWith check above catches the backslash variant.
One thing I noticed: the node: prefix check that was in the original code (specifier.startsWith("node:")) is now redundant since the regex catches it. But removing it was the right move — the regex is more general and handles virtual:, file:, data:, etc. all at once. Clean.
|
|
||
| return specifier.split("/")[0] || null; | ||
| const packageName = specifier.split("/")[0] || null; | ||
| if (!packageName || BUILTIN_MODULES.has(specifier) || BUILTIN_MODULES.has(packageName)) { |
There was a problem hiding this comment.
Checking both specifier and packageName against builtins is a nice touch — handles fs/promises (where the specifier itself is a builtin subpath) and bare builtins like crypto (where packageName equals the specifier). The builtinModules list includes entries like fs/promises directly, so both paths are necessary.
| return null; | ||
| } | ||
|
|
||
| if (specifier.startsWith("@")) { |
There was a problem hiding this comment.
Nit: scoped packages (@scope/pkg) aren't checked against BUILTIN_MODULES before returning. This is fine because no Node builtin starts with @, but it does mean if Node ever added a @node/something builtin (unlikely), it would slip through. Not worth changing, just noting the asymmetry for future readers.
| // which exports `./server` but not `.` or `./package.json`). resolver.resolve() | ||
| // cannot access those hidden paths, but Node still exposes the installed | ||
| // node_modules lookup locations via resolve.paths(). | ||
| const lookupPaths = resolver.resolve.paths(packageName) ?? []; |
There was a problem hiding this comment.
Good fallback strategy. resolve.paths() is stable Node API and gives the same lookup directories that require.resolve() would search. The pkg.name === packageName guard on line 87 prevents false positives from similarly-named directories that aren't the right package (e.g., a stale directory left over from a different version).
|
|
||
| try { | ||
| const plugin = createServerExternalsManifestPlugin(); | ||
| const writeBundle = (plugin.writeBundle as { handler: Function }).handler; |
There was a problem hiding this comment.
Nit: the as { handler: Function } cast is a reasonable workaround for Vite's plugin types (where writeBundle can be either a function or an object with handler). If this pattern shows up in more tests, it might be worth a small getPluginHook test helper to reduce the casting boilerplate, but fine as-is for a single test.
| @@ -0,0 +1,53 @@ | |||
| import { describe, expect, it } from "vite-plus/test"; | |||
There was a problem hiding this comment.
Consider adding a few direct unit tests for packageNameFromSpecifier — it's now exported and the logic is non-trivial (regex, builtin set, scoped packages). The integration test here is valuable but a table-driven unit test would catch regressions faster and document the edge cases explicitly. Not blocking — the integration test covers the important paths.
|
Review submitted. Here's a summary of my findings: Approved — this is a clean, well-tested fix for two real issues:
Minor suggestions in the review: consider adding direct unit tests for the now-exported |
Uh oh!
There was an error while loading. Please reload this page.